/*
#include <sys/mman.h>
#include <fcntl.h>
*/
#include <ShMem.h>
#include <DBChecker.h>
#include <Driver.h>
#include "init_drivers.hpp"

#include <cassert>
#include <cstring>

#include <iostream>

using namespace std;

using namespace CExpert;

void* checker_thread(void* arg){
    CExpert::DBChecker* self = reinterpret_cast<CExpert::DBChecker*>(arg);
    const CExpert::DBChecker::conn_params& cp = self->get_cp();

    while (!self->is_stopped()){
        try{
            if (!CExpert::get_driver(cp.driver)(cp)){
                self->fail();
            } else{
                self->ok();
            }
        }
        catch (const std::exception& ex){
            std::cerr << ex.what() << std::endl;
            self->stop();
        }
        sleep(1);
    }
    return NULL;
}

void do_test(ShMem* sm_write, ShMem* sm_read){
	char buff[ShMem::length] = {0};
	//check for correct size
	memcpy(buff, sm_write->get_memory(), ShMem::length);
	memcpy(sm_write->get_memory(), buff, ShMem::length);
	memcpy(buff, sm_read->get_memory(), ShMem::length);
	cout << "shmem check: 0.";
	sm_write->get_memory()[0] = 0;
	cout << "1." << flush;
	assert(sm_read->get_memory()[0] == 0);
	sm_write->get_memory()[0] = 1;
	cout << "2." << flush;
	assert(sm_read->get_memory()[0] == 1);

	cout << "3." << flush;
	sm_write->get_memory()[100] = 0;
	cout << "4." << flush;
	assert(sm_read->get_memory()[100] == 0);

	cout << "5." << flush;
	sm_write->get_memory()[100] = 130;
	cout << "6" << flush;
	assert(sm_read->get_memory()[100] == 130);
	cout << endl;
}

void do_test_conn_str(){
    std::cout << "conn_str check: 0" << std::endl;
    assert(DBChecker::connstr2filename("mysql://user:passwd@nosuchhostaaabb:7778/nosuchdb") == "mysql.user.nosuchhostaaabb.7778.nosuchdb");
    std::cout << "conn_str check: 1" << std::endl;
    assert(DBChecker::connstr2filename("mysql://user:passwd@nosuchhostaaabb/nosuchdb") == "mysql.user.nosuchhostaaabb..nosuchdb");
    std::cout << "conn_str check: 2" << std::endl;
    assert(DBChecker::connstr2filename("mysql://nosuchhostaaabb/nosuchdb") == "mysql..nosuchhostaaabb..nosuchdb");
    std::cout << "conn_str check: 3" << std::endl;
    assert(DBChecker::connstr2filename("tcp://nosuchhostaaabb") == "tcp..nosuchhostaaabb..");
    std::cout << "conn_str check: 4" << std::endl;
    assert(DBChecker::connstr2filename("tcp://nosuchhostaaabb:1778") == "tcp..nosuchhostaaabb.1778.");
}

int main(){
	try{
        do_test_conn_str();
		ShMem* sm_write = new ShMem("/test", ShMem::OMWRITE);
		ShMem sm_read("/test", ShMem::OMREAD);
		do_test(sm_write, &sm_read);
		//simulating server restart
		delete sm_write;
		sm_write = new ShMem("/test", ShMem::OMWRITE);
		do_test(sm_write, &sm_read);
		delete sm_write;

		DBChecker checker("mysql://user:passwd@nosuchhostaaabb:7778/nosuchdb", true);
		checker.start(&checker_thread);
		sleep(10);
		DBChecker reader("mysql://user:passwd@nosuchhostaaabb:7778/nosuchdb", false);
		for (int i = 0; i < 5; ++i){
			assert(reader.is_ok() == false);
			std::cout << "DBChecker check " << i << std::endl;
			sleep(1);
		}
		//TODO implement success checks
	} catch (const ShMemException & ex){
		perror(NULL);
		std::cerr << ex.what() << " : " << ex.err_no << std::endl;
		return -1;
	}

	return 0;
  /*
  int sh = shm_open("/global", O_RDWR | O_CREAT, 0);
  if (sh == -1){
    std::cerr << "FAIL" << std::endl;
  }
  */

}
